
#define _CRT_SECURE_NO_WARNINGS
#include <assert.h>
#include <tchar.h>
#include <stdio.h>
#include <fstream>
#include <string.h>
#include <string>
#include <sstream>
#include <Shlwapi.h>
#include <algorithm>
#pragma  comment(lib,"Shlwapi.lib") 


#include "config.h"
#include "main.h"




using namespace std;



Config::Config( const char* section, const wchar_t* config_file ) : mConfig(), mSection(section)
{
	if (!config_file)
	{
		 config_file = _T("config.lua");

	}
	mFileName = config_file;


	Default(config_file);
	upDate
	 
}
Config::~Config(void)
{
}

void Config::Default( const wchar_t* strFilePath )
{
	string src(mSection);
	wstring wsFilePath(strFilePath);
	ofstream out;
	bool isNew= false;
	if(!PathFileExists(strFilePath))
	{
		isNew = true;
		out.open(strFilePath,ios_base::out);
		out<<"";
	}
	else
	{
		out.open(strFilePath);
	}
	int len = src.length();
	
	int pos_1 = 0;
	int pos_2 = 0;
	while(pos_2 < len)
	{
		string buf_name;
		string buf_type;
		string buf_value;
		buf_name = "";
		buf_type = "";
		buf_value = "";
		bool key = true;
		for(pos_2 = pos_1; pos_2 < len && key ; pos_2++)
		{
			switch (src[pos_2])
			 {
			case '(':
				buf_name = src.substr(pos_1, pos_2 - pos_1);
				pos_1 = pos_2 + 1;
				break;
			case ')':
				buf_type = src.substr(pos_1, pos_2 - pos_1);
				pos_1 = pos_2 + 1;
				break;
			case '|':
				buf_value = src.substr(pos_1, pos_2 - pos_1);
				pos_1 = pos_2 + 1;
				key = false;
			default:
				break;
			 }
		}
		
		char buf[256];

		if (buf_type == "s")
		{
			sprintf(buf,"%s = '%s'",buf_name.c_str(),buf_value.c_str());
		} 
		else
		{
			sprintf(buf,"%s = %s",buf_name.c_str(),buf_value.c_str());
		}
		
		if(isNew)
		{
			if (buf_type == "s") 
				out<<buf_name<<" = '"<<buf_value<<"'"<<endl;
			else
				out<<buf_name<<" = "<<buf_value<<endl;
			logger->Log("Config Defalut Output: %s >> %s",ws2s(wsFilePath).c_str(),buf);
		}
		
		config_data temp;
		temp.name = buf_name;
		temp.value = buf_value;
		switch(buf_type[0])
		{
		case 'b':
			temp.type = TYPE_BOOLEAN;
			break;
		case 'i':
			temp.type = TYPE_INTEGER;
			break;
		case 'd':
			temp.type = TYPE_NUMBER;
			break;
		case 's':
			temp.type = TYPE_STRING;
			break;
		default:
			logger->Log("Error:variable: %s is unknown type ", ws2s(mFileName), it->name);
			temp.type = TYPE_UNKNOWN;
			break;
		}
		datas.push_back(temp);

	}
	


	out.close();

}
/*
bool Config::isExist( std::string name )
{
	return false;
	
	config_data temp;
	temp.name = name;
	std::vector<int>::iterator result = find( datas.begin(), datas.end( ), temp );
	
}
*/

const Config::config_data* Config::getData( std::string name )
{
	//config_data temp;
	std::vector<config_data>::iterator it;
	for(it = datas.begin();it != datas.end(); ++it)
	{
		if (it->name == name)
		{
			return &(*it);
		}
	}
	return (Config::config_data*)NULL;
}

int Config::getInt( std::string name )
{
	const Config::config_data* temp = getData(name);
	if (temp)
	{
		if (temp->type == TYPE_INTEGER)
		{
			stringstream ss;
			int ret = 0;
			ss<<temp->value;
			ss>>ret;
			return ret;
		}
		logger->Log("Error:In Class Config : error type,name:%s, want type %s but it is %s",
			name.c_str(),
			"integer",
			getTypeName(temp->type));
		assert(false);
	} 

	logger->Log("Error:In Class Config : error name,name:%s",name.c_str());
	assert(false);
	return 0;
}

double Config::getDouble( std::string name )
{
	const Config::config_data* temp = getData(name);
	if (temp)
	{
		if (temp->type == TYPE_NUMBER)
		{
			stringstream ss;
			double ret = 0.0;
			ss<<temp->value;
			ss>>ret;
			return ret;
		}
		logger->Log("Error:In Class Config : error type,name:%s, want type %s but it is %s",
			name.c_str(),
			"double",
			getTypeName(temp->type));
		assert(false);
	} 

	logger->Log("Error:In Class Config : error name,name:%s",name.c_str());
	assert(false);
	return 0;
}

std::string Config::getString( std::string name )
{
	const Config::config_data* temp = getData(name);
	if (temp)
	{
		if (temp->type == TYPE_STRING)
		{
			return temp->value;
		}
		logger->Log("Error:In Class Config : error type,name:%s, want type %s but it is %s",
			name.c_str(),
			"string",
			getTypeName(temp->type));
		assert(false);
	} 

	logger->Log("Error:In Class Config : error name,name:%s",name.c_str());
	assert(false);
	return 0;
}

bool Config::getBool( std::string name )
{
	const Config::config_data* temp = getData(name);
	if (temp)
	{
		if (temp->type == TYPE_BOOLEAN)
		{
			stringstream ss;
			bool ret =false;
			ss<<temp->value;
			ss>>ret;
			return ret;
		}
		logger->Log("Error:In Class Config : error type,name:%s, want type %s but it is %s",
			name.c_str(),
			"bool",
			getTypeName(temp->type));
		assert(false);
	} 

	logger->Log("Error:In Class Config : error name,name:%s",name.c_str());
	assert(false);
	return 0;
}

const char* Config::getTypeName( CONFIG_TYPE type)
{
	switch(type)
	{
	case TYPE_INTEGER:
		return "integer";
	case TYPE_NUMBER:
		return "double";
	case TYPE_BOOLEAN:
		return "bool";
	case TYPE_STRING:
		return "string";
	default:
		return "unknow";
	}
}

void Config::upDate()
{
	int ret = mConfig.DoFile(mFileName.c_str());
	if (ret)
	{
		logger->Log("Error in Class Config->upDate(): %d",ret);
	}
	vector<config_data>::iterator it;
	for (it = datas.begin(); it != datas.end(); ++it)
	{
		stringstream value_buff;
		value_buff.str("");
		switch(it->type)
		{
		case TYPE_BOOLEAN:
			value_buff<<mConfig.GetGlobalBool(it->name);
			break;
		case TYPE_NUMBER:
			value_buff<<mConfig.GetGlobalInt(it->name);
			break;
		case TYPE_INTEGER:
			value_buff<<mConfig.GetGlobalDouble(it->name);
			break;
		case TYPE_STRING:
			value_buff<<mConfig.GetGlobalString(it->name);
			break;
		case TYPE_UNKNOWN:
		default:
			value_buff<<"nil";
			logger->Log("Error:Cannot update config file: %s with variable: %s of unknown type ", ws2s(mFileName), it->name);
			break;
		}
		it->value = value_buff;
	}
}

void Config::saveToFile( const wchar_t* config_file /*= NULL*/ )
{
	wstring file_name_for_save;
	if (config_file == NULL)
	{
		file_name_for_save = mFileName;
	}
	ofstream file_stream_for_save(file_name_for_save,ios::out);
	
	vector<config_data>::iterator it;
	for (it = datas.begin(); it != datas.end(); ++it)
	{
		file_stream_for_save<<it->name<<" = ";
		if (it->type == TYPE_STRING)
		{
			file_stream_for_save<<"'"<<it->value<<"'"<<endl;
		} 
		else
		{
			file_stream_for_save<<it->value<<endl;
		}

	}

}
